Skip to content

feat(player): add subtitle search functionality#217

Merged
mkdir700 merged 2 commits intodevfrom
mkdir700/subtitle-list-search
Oct 15, 2025
Merged

feat(player): add subtitle search functionality#217
mkdir700 merged 2 commits intodevfrom
mkdir700/subtitle-list-search

Conversation

@mkdir700
Copy link
Owner

@mkdir700 mkdir700 commented Oct 15, 2025

Summary by CodeRabbit

  • 新功能
    • 播放器新增字幕搜索:顶部入口,一键开启;实时高亮匹配、结果计数/空态/加载提示;支持 Esc 关闭,搜索框内阻止空格误触发。
  • 体验改进
    • 输入文字时默认不触发全局快捷键,降低误操作风险(可配置允许)。
  • 国际化
    • 新增字幕搜索相关文案,覆盖简体中文、英文、日文、俄文、繁体中文;优化部分中文提示与快捷键描述。

Summary by CodeRabbit

  • 新功能
    • 播放器新增“字幕搜索”入口与面板:支持输入搜索、高亮匹配、结果统计(含加载中/无结果状态)与清空/关闭操作。
  • 体验改进
    • 默认在输入文字时不触发全局快捷键,降低误触风险(可按需允许)。
    • 播放器相关提示气泡交互更一致。
  • 本地化
    • 补充并优化字幕搜索相关文案,覆盖英文、日文、俄文、简体中文、繁体中文。
    • 更新部分提示与快捷键文案(含新增自动暂停切换)。

- Implement subtitle search feature across multiple locales
- Add new translations for subtitle search in en-us, ja-jp, ru-ru, and zh-cn
- Create SubtitleSearchHighlight component for highlighting search results
- Update player-ui store to manage subtitle search visibility state
- Introduce actions to toggle, show, and hide subtitle search
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 15, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

在播放器新增“字幕搜索”功能:添加可见性状态与控制方法,页面顶部加入搜索入口,SubtitleList 面板实现输入搜索、结果高亮与节流/键盘交互,并扩展多语言 i18n 文案(en/ja/ru/zh-CN/zh-TW)。快捷键 Hook 增加“输入时禁止触发”的选项。

Changes

Cohort / File(s) Change Summary
字幕搜索 UI 与交互
src/renderer/src/pages/player/components/SubtitleListPanel.tsx, src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
新增搜索面板与高亮组件:搜索输入、加载态、统计/空状态、结果列表、匹配高亮、ESC 关闭、空格键处理、300ms 防抖与查询过滤逻辑;渲染切换搜索与原有字幕列表。
播放器导航入口
src/renderer/src/pages/player/PlayerPage.tsx
在顶部导航添加“字幕搜索”图标与 Tooltip,调用 store 的 toggleSubtitleSearch 控制面板显示。
播放器 UI Store
src/renderer/src/state/stores/player-ui.store.ts
新增状态 subtitleSearch.isSearchVisible,并新增操作:toggleSubtitleSearch()showSubtitleSearch()hideSubtitleSearch()
快捷键 Hook 行为
src/renderer/src/infrastructure/hooks/useShortcut.ts
UseShortcutOptions 增加 allowWhenTyping?: boolean(默认 false);引入输入态检测(input/textarea/contentEditable 等),在输入时(typingActive)阻止快捷键触发;全局与条目级 enabled 一并判断。
i18n:新增字幕搜索文案(多语言)
src/renderer/src/i18n/locales/en-us.json, .../ja-jp.json, .../ru-ru.json, .../zh-tw.json
player.subtitleList 下新增 emptysearch 键:placeholder、pending、count(含复数变体)、none、emptyTitle、emptySubtitle、empty.description/title 等本地化字符串。
i18n:zh-CN 扩展与重构
src/renderer/src/i18n/locales/zh-cn.json
增加 player.subtitleList 文案并对若干区块重排/扩展(mask-mode、dictionary、mediaServerPrompt、FFprobe/FFmpeg 下载提示、shortcuts.toggle_auto_pause 等),保留语义并引入额外翻译键。

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User as 用户
  participant Navbar as PlayerPage Navbar
  participant Store as PlayerUI Store
  participant Panel as SubtitleListPanel
  participant HL as HighlightedText

  User->>Navbar: 点击“字幕搜索”图标
  Navbar->>Store: toggleSubtitleSearch()
  Store-->>Navbar: isSearchVisible = true
  Store-->>Panel: isSearchVisible 变更
  Panel->>Panel: 聚焦搜索输入框
  User->>Panel: 输入查询(debounce 300ms)
  Panel->>Panel: 过滤字幕行并统计结果
  Panel->>HL: 请求高亮渲染
  HL-->>Panel: 返回高亮片段
  User->>Panel: 按 ESC
  Panel->>Store: hideSubtitleSearch()
  Store-->>Panel: isSearchVisible = false
Loading
sequenceDiagram
  autonumber
  actor User as 用户
  participant Doc as 输入控件(input/textarea/可编辑)
  participant Hook as useShortcut
  participant App as 回调处理

  User->>Doc: 正在输入
  Hook->>Hook: 检测 typingActive = true
  alt allowWhenTyping = false
    Hook--x App: 阻止触发快捷键
  else allowWhenTyping = true
    Hook->>App: 触发快捷键回调
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

我是一只小兔子,跳进字幕林,
搜索一行词,银光把字点晶。
ESC 轻轻一按,面板归回宁静,
键盘若在输入,快捷暂不惊。
多语添新词,兔子心里欢欣。 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 此标题简洁明确地概括了该PR在播放器中新增字幕搜索功能的核心更改,与实际改动内容高度一致且遵循常见的feat(scope): 描述风格,有助于团队快速识别历史记录。
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mkdir700/subtitle-list-search

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f584120 and 32e43b5.

📒 Files selected for processing (1)
  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
src/renderer/src/**/*.{ts,tsx,scss,css}

📄 CodeRabbit inference engine (CLAUDE.md)

优先使用 CSS 变量,避免硬编码样式值(颜色等)

Files:

  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
src/renderer/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

尺寸与时长等不要硬编码,优先使用 useTheme() 的 token 或集中样式变量(如 motionDurationMid、borderRadiusSM/MD)

Files:

  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: 定制 antd 组件样式优先使用 styled-components 包装 styled(Component),避免全局 classNames
项目的图标统一使用 lucide-react,不使用 emoji 作为图标
组件/Hook 顶层必须通过 useStore(selector) 使用 Zustand,禁止在 useMemo/useEffect 内部调用 store Hook
避免使用返回对象的 Zustand 选择器(如 useStore(s => ({ a: s.a, b: s.b })));应使用单字段选择器或配合 shallow 比较器
遵循 React「副作用与状态更新」规范:渲染纯函数、Effect 三分法、幂等更新、稳定引用、严格清理、禁止写回自身依赖、Provider 值 memo、外部状态 selector 稳定等
统一使用 loggerService 记录日志而不是 console
logger 使用示例中第二个参数必须为对象字面量(如 logger.error('msg', { error }))
任何组件或页面都不要写入 media 元素的 currentTime,播放器控制由编排器统一负责
在 styled-components 中:主题相关属性使用 AntD CSS 变量(如 var(--ant-color-bg-elevated));
在 styled-components 中:设计系统常量(尺寸、动画、层级、字体、毛玻璃等)使用 JS 常量(如 SPACING、BORDER_RADIUS、Z_INDEX、FONT_SIZES 等)

Files:

  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
**/player/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Player 页面:统一在组件顶层使用 Zustand selector,禁止在 useMemo/useEffect 内调用 store Hook;useSubtitleEngine 通过参数传入 subtitles 等防御处理

Files:

  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
🧠 Learnings (2)
📚 Learning: 2025-09-17T14:59:36.985Z
Learnt from: CR
PR: mkdir700/EchoPlayer#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T14:59:36.985Z
Learning: Applies to src/renderer/src/**/*.{ts,tsx} : 尺寸与时长等不要硬编码,优先使用 useTheme() 的 token 或集中样式变量(如 motionDurationMid、borderRadiusSM/MD)

Applied to files:

  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
📚 Learning: 2025-09-17T14:59:36.985Z
Learnt from: CR
PR: mkdir700/EchoPlayer#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T14:59:36.985Z
Learning: Applies to **/*.{ts,tsx} : 在 styled-components 中:设计系统常量(尺寸、动画、层级、字体、毛玻璃等)使用 JS 常量(如 SPACING、BORDER_RADIUS、Z_INDEX、FONT_SIZES 等)

Applied to files:

  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
🧬 Code graph analysis (1)
src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx (1)
src/renderer/src/infrastructure/styles/theme.ts (1)
  • SPACING (43-58)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test (ubuntu-latest, 20)
  • GitHub Check: test (windows-latest, 20)
  • GitHub Check: test (macos-latest, 20)
🔇 Additional comments (2)
src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx (2)

15-40: 实现质量优秀,防御性编程到位。

组件逻辑清晰且健壮:

  • 空查询早返回优化性能
  • 正则表达式转义完整(覆盖所有特殊字符)
  • 使用捕获组配合 toLowerCase() 比较正确识别匹配片段(split 保留原始大小写,需要 toLowerCase 判断)
  • Try-catch 处理正则异常,回退到原始文本
  • 使用 memo 避免不必要的重渲染

46-58: 正确使用了设计系统常量。

样式实现符合编码规范:

  • 颜色使用 CSS 变量(var(--ant-color-warning-bg) 等)
  • 尺寸使用设计系统常量(SPACING.XXS / 2)而非硬编码值
  • 深色主题覆盖实现完整

之前的反馈已正确处理:paddingborder-radius 现在使用 SPACING.XXS / 2 (4px / 2 = 2px),而非硬编码的 2px


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13273fc and f584120.

📒 Files selected for processing (10)
  • src/renderer/src/i18n/locales/en-us.json (1 hunks)
  • src/renderer/src/i18n/locales/ja-jp.json (1 hunks)
  • src/renderer/src/i18n/locales/ru-ru.json (1 hunks)
  • src/renderer/src/i18n/locales/zh-cn.json (4 hunks)
  • src/renderer/src/i18n/locales/zh-tw.json (1 hunks)
  • src/renderer/src/infrastructure/hooks/useShortcut.ts (2 hunks)
  • src/renderer/src/pages/player/PlayerPage.tsx (4 hunks)
  • src/renderer/src/pages/player/components/SubtitleListPanel.tsx (9 hunks)
  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx (1 hunks)
  • src/renderer/src/state/stores/player-ui.store.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
src/renderer/src/**/*.{ts,tsx,scss,css}

📄 CodeRabbit inference engine (CLAUDE.md)

优先使用 CSS 变量,避免硬编码样式值(颜色等)

Files:

  • src/renderer/src/pages/player/PlayerPage.tsx
  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
  • src/renderer/src/pages/player/components/SubtitleListPanel.tsx
  • src/renderer/src/state/stores/player-ui.store.ts
  • src/renderer/src/infrastructure/hooks/useShortcut.ts
src/renderer/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

尺寸与时长等不要硬编码,优先使用 useTheme() 的 token 或集中样式变量(如 motionDurationMid、borderRadiusSM/MD)

Files:

  • src/renderer/src/pages/player/PlayerPage.tsx
  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
  • src/renderer/src/pages/player/components/SubtitleListPanel.tsx
  • src/renderer/src/state/stores/player-ui.store.ts
  • src/renderer/src/infrastructure/hooks/useShortcut.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: 定制 antd 组件样式优先使用 styled-components 包装 styled(Component),避免全局 classNames
项目的图标统一使用 lucide-react,不使用 emoji 作为图标
组件/Hook 顶层必须通过 useStore(selector) 使用 Zustand,禁止在 useMemo/useEffect 内部调用 store Hook
避免使用返回对象的 Zustand 选择器(如 useStore(s => ({ a: s.a, b: s.b })));应使用单字段选择器或配合 shallow 比较器
遵循 React「副作用与状态更新」规范:渲染纯函数、Effect 三分法、幂等更新、稳定引用、严格清理、禁止写回自身依赖、Provider 值 memo、外部状态 selector 稳定等
统一使用 loggerService 记录日志而不是 console
logger 使用示例中第二个参数必须为对象字面量(如 logger.error('msg', { error }))
任何组件或页面都不要写入 media 元素的 currentTime,播放器控制由编排器统一负责
在 styled-components 中:主题相关属性使用 AntD CSS 变量(如 var(--ant-color-bg-elevated));
在 styled-components 中:设计系统常量(尺寸、动画、层级、字体、毛玻璃等)使用 JS 常量(如 SPACING、BORDER_RADIUS、Z_INDEX、FONT_SIZES 等)

Files:

  • src/renderer/src/pages/player/PlayerPage.tsx
  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
  • src/renderer/src/pages/player/components/SubtitleListPanel.tsx
  • src/renderer/src/state/stores/player-ui.store.ts
  • src/renderer/src/infrastructure/hooks/useShortcut.ts
**/player/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Player 页面:统一在组件顶层使用 Zustand selector,禁止在 useMemo/useEffect 内调用 store Hook;useSubtitleEngine 通过参数传入 subtitles 等防御处理

Files:

  • src/renderer/src/pages/player/PlayerPage.tsx
  • src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx
  • src/renderer/src/pages/player/components/SubtitleListPanel.tsx
**/{stores,infrastructure,persistence}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Zustand 状态管理按三层架构组织:stores、infrastructure、persistence

Files:

  • src/renderer/src/state/stores/player-ui.store.ts
  • src/renderer/src/infrastructure/hooks/useShortcut.ts
🧠 Learnings (2)
📚 Learning: 2025-09-17T14:59:36.985Z
Learnt from: CR
PR: mkdir700/EchoPlayer#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T14:59:36.985Z
Learning: Applies to **/player/**/*.{ts,tsx} : Player 页面:统一在组件顶层使用 Zustand selector,禁止在 useMemo/useEffect 内调用 store Hook;useSubtitleEngine 通过参数传入 subtitles 等防御处理

Applied to files:

  • src/renderer/src/pages/player/PlayerPage.tsx
  • src/renderer/src/pages/player/components/SubtitleListPanel.tsx
📚 Learning: 2025-09-17T14:59:36.985Z
Learnt from: CR
PR: mkdir700/EchoPlayer#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-17T14:59:36.985Z
Learning: Applies to **/*.{ts,tsx} : 在 styled-components 中:设计系统常量(尺寸、动画、层级、字体、毛玻璃等)使用 JS 常量(如 SPACING、BORDER_RADIUS、Z_INDEX、FONT_SIZES 等)

Applied to files:

  • src/renderer/src/pages/player/components/SubtitleListPanel.tsx
🧬 Code graph analysis (2)
src/renderer/src/pages/player/PlayerPage.tsx (2)
src/renderer/src/state/stores/player-ui.store.ts (1)
  • usePlayerUIStore (119-121)
src/renderer/src/pages/player/components/index.ts (1)
  • NavbarIcon (15-47)
src/renderer/src/pages/player/components/SubtitleListPanel.tsx (3)
src/renderer/src/infrastructure/types/subtitle.ts (1)
  • SubtitleItem (10-16)
src/renderer/src/state/stores/player-ui.store.ts (1)
  • usePlayerUIStore (119-121)
src/renderer/src/infrastructure/styles/theme.ts (2)
  • SPACING (43-58)
  • BORDER_RADIUS (61-72)
🪛 Biome (2.1.2)
src/renderer/src/pages/player/components/SubtitleListPanel.tsx

[error] 225-225: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 384-384: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 389-389: The elements with this role can be changed to the following elements:

      For examples and more information, see WAI-ARIA Roles

      (lint/a11y/useSemanticElements)


      [error] 393-394: The elements with this role can be changed to the following elements:

    • For examples and more information, see WAI-ARIA Roles

      (lint/a11y/useSemanticElements)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test (windows-latest, 20)
  • GitHub Check: test (ubuntu-latest, 20)
  • GitHub Check: test (macos-latest, 20)
🔇 Additional comments (21)
src/renderer/src/i18n/locales/zh-tw.json (1)

98-116: LGTM!

繁體中文本地化新增的字幕列表相關文案結構完整,包含空狀態和搜索狀態的所有必要文案,並且正確使用了複數形式(count_one、count_other)。

src/renderer/src/pages/player/components/SubtitleSearchHighlight.tsx (1)

14-39: 組件實現正確,錯誤處理完善。

HighlightedText 組件正確實現了關鍵詞高亮功能:

  • 使用正則轉義處理特殊字符
  • 不區分大小寫匹配
  • 提供了錯誤降級處理
src/renderer/src/pages/player/PlayerPage.tsx (1)

97-97: LGTM!

正確在組件頂層使用 Zustand selector,符合編碼規範中的要求。

根據學習記錄

src/renderer/src/i18n/locales/ja-jp.json (1)

137-155: LGTM!

日文本地化新增的字幕列表文案結構完整,與其他語言保持一致。

src/renderer/src/infrastructure/hooks/useShortcut.ts (3)

13-21: LGTM!

新增的 allowWhenTyping 選項設計合理,默認值為 false 可防止快捷鍵在輸入時意外觸發,這對於新增的字幕搜索功能很重要。


23-66: 輸入檢測邏輯實現完善。

NON_TYPABLE_INPUT_TYPES 集合和 isTypingInput 函數正確識別了各種輸入場景:

  • 涵蓋了 contentEditable、textarea、select 等元素
  • 正確排除了按鈕、checkbox 等非文本輸入類型
  • 實現邏輯清晰,考慮周全

93-110: 快捷鍵防護邏輯正確。

輸入狀態檢測邏輯實現合理:

  • 正確獲取當前聚焦元素
  • Escape 鍵被豁免(這對於關閉搜索面板很重要)
  • enabled 檢查同時考慮了 options.enabled 和 shortcutConfig.enabled
src/renderer/src/i18n/locales/en-us.json (1)

89-105: LGTM!

英文本地化新增的字幕列表文案清晰自然,複數形式處理正確。

src/renderer/src/state/stores/player-ui.store.ts (2)

14-16: LGTM!

新增的 subtitleSearch 狀態樹和三個操作方法(toggle/show/hide)設計清晰,符合狀態管理的最佳實踐。

Also applies to: 27-29


100-116: 狀態操作實現正確。

三個 action 的實現邏輯正確:

  • toggleSubtitleSearch:正確切換布爾值
  • showSubtitleSearch:顯式設為 true
  • hideSubtitleSearch:顯式設為 false

使用 Immer Draft 進行不可變更新,符合 Zustand 最佳實踐。

src/renderer/src/pages/player/components/SubtitleListPanel.tsx (6)

59-63: LGTM!

正確在組件頂層使用 Zustand selector,符合編碼規範要求。

根據學習記錄


72-84: 搜索結果計算邏輯正確。

searchResultsuseMemo 實現正確:

  • 依賴項包含 subtitlesnormalizedQuery
  • 使用 reduce 避免中間數組分配
  • 大小寫不敏感匹配邏輯正確

165-177: 搜索防抖實現正確。

防抖邏輯實現合理:

  • 有查詢時立即設置 isSearching 為 true
  • 300ms 後設置為 false,提供視覺反饋
  • 正確清理 timeout

220-245: LGTM!搜索 UI 樣式符合設計規範。

搜索控制欄的樣式實現遵循了編碼規範:

  • 使用 SPACINGBORDER_RADIUS 常量(符合規範要求)
  • 使用 AntD CSS 變量(如 var(--color-background-soft)
  • 動畫實現流暢,過渡效果合理
  • 響應式設計考慮周全(focus-within 狀態)

根據學習記錄

Also applies to: 556-697


349-398: 搜索結果面板實現完善。

SubtitleSearchResultsPanel 組件實現正確:

  • 使用 i18n 提供本地化文案
  • 空狀態處理清晰
  • 使用 HighlightedText 高亮匹配文本
  • 正確傳遞 onSelect 回調

146-162: 保留空格键阻止逻辑
allowWhenTyping 仅阻止 useShortcut 的回调,不拦截事件冒泡;handleSearchKeyDown 中的 stopPropagation 必须保留,以防止空格键触发全局播放/暂停。

src/renderer/src/i18n/locales/zh-cn.json (5)

439-439: 为 FFprobe 增加“安装”按钮文案:LGTM

与 FFmpeg 匹配,提升一致性。


509-509: 确认 toggle_auto_pause 快捷键映射与 i18n key 一致:已在 usePlayerShortcuts、shortcuts.const.ts、label.ts 及各语言包中同步。


190-211: mediaServerPrompt 结构清晰,文案妥当

actions、benefits、subtitle、title 结构化良好,无歧义。

请手动确认其他语言文件已同步新增 mediaServerPrompt 及其子键,避免界面多语言混用。


213-216: 补充或确认其他语言包中的字幕功能键
zh-CN 已加入 player.subtitles.hide、player.subtitles.search、player.subtitles.show。请检查并确保 ru-RU、en-US、ja-JP、zh-TW 等所有 locale 文件的 subtitles 对象中包含“hide”、“search”、“show”三键。


106-120: 确认已更新所有 mask-mode 与 display-mode 路径引用
已在 SubtitleOverlay.tsx 和 CaptionsButton.tsx 中使用 player.controls.subtitle.mask-mode.*,未发现旧路径引用。

Comment on lines +98 to +116
"player": {
"subtitleList": {
"empty": {
"title": "В той же папке, что и видео, не найден подходящий файл субтитров",
"description": "Вы можете выбрать файл субтитров с помощью кнопки ниже или перетащить его в эту область"
},
"search": {
"placeholder": "Поиск субтитров...",
"pending": "Поиск...",
"count": "Найден {{count}} файл субтитров",
"count_one": "Найден {{count}} файл субтитров",
"count_few": "Найдено {{count}} файла субтитров",
"count_many": "Найдено {{count}} файлов субтитров",
"count_other": "Найдено {{count}} субтитров",
"none": "Субтитры по запросу не найдены",
"emptyTitle": "Совпадений не найдено",
"emptySubtitle": "Попробуйте другой запрос"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

复数形式基本正确;建议补齐字幕面板按钮文案(跨语言一致性)

  • 俄语复数键 count_one/few/many/other 配置合理;占位符 {{count}} 正确。
  • 但本地化中缺少字幕面板按钮键:player.subtitles.hide/search/show(在 zh-cn 已新增)。缺失将导致退回默认语言或出现占位键。

建议在本文件补齐如下键值:

   "player": {
+    "subtitles": {
+      "hide": "Скрыть список субтитров",
+      "search": "Поиск субтитров",
+      "show": "Показать список субтитров"
+    },
     "subtitleList": {

请确认代码调用路径为 t('player.subtitleList.search.count', { count }),以使用 i18next 复数推断。若需要,我可批量为所有语言包补齐缺失键并提交补丁。


正在验证 ru-ru.json 是否包含 player.subtitles 键,并检查代码中是否使用 t('player.subtitleList.search.count', { count }) 调用。


🏁 Script executed:

#!/bin/bash
rg -nP '"subtitles"\s*:' -n src/renderer/src/i18n/locales/ru-ru.json
rg -nP '"subtitles"\s*:' -n src/renderer/src/i18n/locales/zh-cn.json
rg -nP "t\(['\"]player\.subtitleList\.search\.count" -C2 -n src/renderer/src

Length of output: 645


🏁 Script executed:

#!/bin/bash
sed -n '190,240p' src/renderer/src/i18n/locales/ru-ru.json
rg -nP '"player"\s*:' -n src/renderer/src/i18n/locales/zh-cn.json -C10

Length of output: 557


🏁 Script executed:

#!/bin/bash
rg -nP '"subtitles":\s*{' -n -A15 src/renderer/src/i18n/locales/ru-ru.json

Length of output: 0


🏁 Script executed:

#!/bin/bash
sed -n '200,260p' src/renderer/src/i18n/locales/ru-ru.json

Length of output: 0


🏁 Script executed:

#!/bin/bash
FILE=src/renderer/src/i18n/locales/ru-ru.json
ls -l "$FILE"
wc -l "$FILE"
rg -n "Скрыть список" "$FILE"
rg -n "Показать список" "$FILE"
rg -n "Поиск субтитров" "$FILE"

Length of output: 183


添加播放器字幕面板按钮翻译键

ru-ru.json 和 zh-cn.json 均缺少 player.subtitles.hide、search、show 三个键,需补充以保持跨语言一致性并避免回退默认语言。

建议在各自语言包的 player 节点下添加:

   "player": {
+    "subtitles": {
+      "hide": "Скрыть список субтитров",      // 隐藏字幕列表
+      "search": "Поиск субтитров",            // 搜索字幕
+      "show": "Показать список субтитров"     // 显示字幕列表
+    },
     "subtitleList": {
       …  
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"player": {
"subtitleList": {
"empty": {
"title": "В той же папке, что и видео, не найден подходящий файл субтитров",
"description": "Вы можете выбрать файл субтитров с помощью кнопки ниже или перетащить его в эту область"
},
"search": {
"placeholder": "Поиск субтитров...",
"pending": "Поиск...",
"count": "Найден {{count}} файл субтитров",
"count_one": "Найден {{count}} файл субтитров",
"count_few": "Найдено {{count}} файла субтитров",
"count_many": "Найдено {{count}} файлов субтитров",
"count_other": "Найдено {{count}} субтитров",
"none": "Субтитры по запросу не найдены",
"emptyTitle": "Совпадений не найдено",
"emptySubtitle": "Попробуйте другой запрос"
}
}
"player": {
"subtitles": {
"hide": "Скрыть список субтитров",
"search": "Поиск субтитров",
"show": "Показать список субтитров"
},
"subtitleList": {
"empty": {
"title": "В той же папке, что и видео, не найден подходящий файл субтитров",
"description": "Вы можете выбрать файл субтитров с помощью кнопки ниже или перетащить его в эту область"
},
"search": {
"placeholder": "Поиск субтитров...",
"pending": "Поиск...",
"count": "Найден {{count}} файл субтитров",
"count_one": "Найден {{count}} файл субтитров",
"count_few": "Найдено {{count}} файла субтитров",
"count_many": "Найдено {{count}} файлов субтитров",
"count_other": "Найдено {{count}} субтитров",
"none": "Субтитры по запросу не найдены",
"emptyTitle": "Совпадений не найдено",
"emptySubtitle": "Попробуйте другой запрос"
}
}
🤖 Prompt for AI Agents
In src/renderer/src/i18n/locales/ru-ru.json around lines 98-116, the locale is
missing the player.subtitles keys (hide, search, show); add these three keys
under the existing player node so translations match other locales and prevent
fallback to the default language—use appropriate Russian strings such as "Скрыть
субтитры" for hide, "Поиск субтитров" for search, and "Показать субтитры" for
show (ensure JSON syntax and comma placement are correct).

Comment on lines +123 to +129
"dictionary": {
"error": "查询失败",
"loading": "查询中...",
"more_definitions": "... 还有 {{count}} 个释义",
"pronunciation": "点击发音",
"translations": "常用翻译"
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

“dictionary” 放于 player 命名空间;核对各处引用是否一致

若组件期望根级 dictionary.* 将导致缺失;请统一为 player.dictionary.* 或调整代码。

可用脚本核对所有引用与各语言包是否存在相同路径:


🏁 Script executed:

#!/bin/bash
echo "代码引用:"
rg -n -C2 "t\\(['\"]player\\.dictionary\\." src || true
echo "Locale 存在性:"
fd -a -g "src/renderer/src/i18n/locales/*.json" | xargs -I{} rg -n "player\"\\s*:\\s*\\{[^}]*\"dictionary\"" -n {}

Length of output: 1654


本地化键与代码使用不一致: 代码中使用了 player.dictionary.*,但语言包(如 src/renderer/src/i18n/locales/zh-cn.json)将 dictionary 放在根级,导致翻译无法加载。请将 dictionary 节点移入 player 命名空间,或调整代码引用为根级 dictionary.*

🤖 Prompt for AI Agents
In src/renderer/src/i18n/locales/zh-cn.json around lines 123 to 129 the
localization keys are defined under a root-level "dictionary" object while the
application expects translations under "player.dictionary.*"; move the existing
"dictionary" node inside a new or existing "player" namespace (i.e., nest
"dictionary" under "player") so keys become player.dictionary.error,
player.dictionary.loading, etc., or alternatively update code to reference the
root-level dictionary keys (change usages from player.dictionary.* to
dictionary.*) — choose the approach consistent with other locale files and keep
key structure identical after the change.

Comment on lines +217 to +231
"subtitleList": {
"empty": {
"title": "在视频文件同目录下未找到匹配的字幕文件",
"description": "您可以点击下方按钮选择字幕文件,或将字幕文件拖拽到此区域"
},
"search": {
"placeholder": "搜索字幕...",
"pending": "搜索中...",
"count": "找到 {{count}} 条字幕",
"count_one": "找到 {{count}} 条字幕",
"count_other": "找到 {{count}} 条字幕",
"none": "未找到匹配的字幕",
"emptyTitle": "未找到匹配结果",
"emptySubtitle": "请尝试其他关键词"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

subtitleList 搜索文案完备;可精简多余复数键(可选)

中文不需要复数变体,保留 count_other 足够;count 与 count_one 可视为冗余(不必改也无害)。

🤖 Prompt for AI Agents
In src/renderer/src/i18n/locales/zh-cn.json around lines 217 to 231, the
subtitleList.search plural keys are redundant for Chinese; remove the
unnecessary "count" and "count_one" entries and keep a single "count" or
"count_other" key (preferably "count") with value "找到 {{count}} 条字幕" to simplify
the locale file while preserving behavior.

Comment on lines +220 to +245
{isSearchVisible && (
<ControlBar>
<SearchInputContainer>
<SearchIconWrapper>
{isSearching ? <Loader2 size={14} className="spin" /> : <Search size={14} />}
</SearchIconWrapper>
<SearchInput
ref={searchInputRef}
type="text"
value={searchQuery}
onChange={handleSearchChange}
onKeyDown={handleSearchKeyDown}
placeholder={t('player.subtitleList.search.placeholder')}
autoComplete="off"
/>
{searchQuery && (
<ClearButton onClick={handleSearchClear}>
<X size={14} />
</ClearButton>
)}
<CloseButton onClick={handleSearchClose}>
<X size={16} />
</CloseButton>
</SearchInputContainer>
</ControlBar>
)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

考慮遵循靜態分析工具的語義化建議。

Biome 靜態分析工具指出以下 ARIA role 可以替換為語義化 HTML 元素:

  • Line 225: role="complementary"<aside>
  • Line 384: role="status"<output>
  • Line 389: role="list"<ul><ol>
  • Line 393-394: role="listitem"<li>

雖然當前實現功能正確,但使用語義化元素可以提高可訪問性並減少代碼複雜度。

示例重構(僅供參考):

 return (
-  <Container role="complementary" aria-label="caption-list">
+  <Container as="aside" aria-label="caption-list">
     {/* ... */}
   </Container>
 )

 function SubtitleSearchResultsPanel({...}) {
   if (results.length === 0) {
     return (
-      <SearchResultsEmpty role="status">
+      <SearchResultsEmpty as="output">
         {/* ... */}
       </SearchResultsEmpty>
     )
   }

   return (
-    <SearchResultsList role="list" aria-label="subtitle-search-results">
+    <SearchResultsList as="ul" aria-label="subtitle-search-results">
       {results.map(({ subtitle, index }) => (
-        <SearchResultItem key={subtitle.id} role="listitem" /* ... */>
+        <SearchResultItem as="li" key={subtitle.id} /* ... */>
           {/* ... */}
         </SearchResultItem>
       ))}
     </SearchResultsList>
   )
 }

Also applies to: 349-398

🧰 Tools
🪛 Biome (2.1.2)

[error] 225-225: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)

🤖 Prompt for AI Agents
In src/renderer/src/pages/player/components/SubtitleListPanel.tsx around lines
220-245 (and also apply similar changes to 349-398), several elements use ARIA
role attributes where semantic HTML elements would be appropriate: replace
elements with role="complementary" with an <aside>, role="status" with an
<output>, role="list" with a semantic <ul> or <ol>, and role="listitem" with
<li>; update the JSX structure accordingly (move children into the new semantic
containers, remove the redundant role attributes, and ensure any styling or
refs/props are preserved) so accessibility and static-analysis warnings are
resolved.

Comment on lines +605 to +609
<Tooltip title={t('player.subtitles.search')} mouseEnterDelay={0.8}>
<NavbarIcon onClick={toggleSubtitleSearch}>
<Search size={18} />
</NavbarIcon>
</Tooltip>
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

驗證 i18n 鍵是否存在。

第 605 行引用了翻譯鍵 'player.subtitles.search',但在提供的所有本地化文件中,新增的鍵路徑是 player.subtitleList.* 而非 player.subtitles.search。請確認此鍵是否存在,或者應該使用不同的鍵。

運行以下腳本驗證翻譯鍵的使用:


🏁 Script executed:

#!/bin/bash
# 描述:在本地化文件中搜索 player.subtitles.search 鍵
# 預期:找到該鍵的定義或確認應使用其他鍵

# 搜索 player.subtitles.search
echo "=== 搜索 player.subtitles.search ==="
rg -n "subtitles.*search" src/renderer/src/i18n/locales/

# 搜索所有 player.subtitle 相關的鍵
echo "=== 搜索所有 player 下的 subtitle 相關鍵 ==="
rg -n '"subtitle' src/renderer/src/i18n/locales/ -A 2

Length of output: 3807


确保 i18n 键 'player.subtitles.search' 在所有本地化文件中定义
zh-CN 已包含该键,但 en-US、ru-RU、ja-JP 等缺失,请在对应 locales 文件中补充该翻译。

🤖 Prompt for AI Agents
In src/renderer/src/pages/player/PlayerPage.tsx around lines 605 to 609 the
Tooltip uses the i18n key 'player.subtitles.search' but that key only exists in
zh-CN; add the missing 'player.subtitles.search' entry to each locales file
(e.g., src/renderer/locales/en-US.json, ru-RU.json, ja-JP.json and any other
supported locale files) with appropriate translations, keep the JSON structure
consistent with existing locale files, then run the i18n lint/build step (or the
project's locale validation script) to ensure no missing keys remain.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex adress that feedback

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Testing

  • ⚠️ Not run (not requested)

View task →

@mkdir700 mkdir700 merged commit 4f92205 into dev Oct 15, 2025
5 checks passed
@mkdir700 mkdir700 deleted the mkdir700/subtitle-list-search branch October 15, 2025 11:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant